package com.communal.service.impl;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.communal.dao.IModelDao;
import com.communal.dao.IRoleDao;
import com.communal.dao.IUserDao;
import com.communal.model.Model;
import com.communal.model.Role;
import com.communal.model.User;
import com.communal.service.IUserService;
import com.communal.util.AppConstants;
import com.communal.util.AppException;
import com.communal.web.form.UserInfoForm;

/**
 * Implements operations for user (registration, changing profile, e.t.s)
 * @author Created by andrey.kuznetsov <br>
 * @author Last modified by $Author$ <br>
 * @author Last modified on $Date$ at revision $Revision$ <br>
 */
@Service
public class UserService extends AbstractService implements IUserService{
	
	@Autowired 
	private IUserDao userDao;
	
	@Autowired
	private IModelDao modelDao;

	@Autowired 
	private IRoleDao roleDao;
	
	@Override
	@Transactional(readOnly=true)
	public Model getModelForCurrentLoggedUser() throws AppException {
		SecurityContext securityContext = SecurityContextHolder.getContext();
		Model model = null; 
		if(securityContext == null || securityContext.getAuthentication() == null || securityContext.getAuthentication().getPrincipal() == null){
			throw new AppException( messageSource.getMessage( "message.error.authorization.common", null, null ));
		}
		String login = null;
		Object principal = securityContext.getAuthentication().getPrincipal();
		if(principal instanceof UserDetails){
			login =((org.springframework.security.core.userdetails.User) principal).getUsername();
		}else {
			login = principal.toString();
		}
		
		if(StringUtils.isNotEmpty( login )){
			User userDB = userDao.getUserByLogin( login );
			if(userDB != null){
				model = userDB.getModel();
			}else{
				throw new AppException( 
						messageSource.getMessage( "message.error.authorization.user.null", new Object[]{login}, null ) );
			}
		}else{
			throw new AppException( 
					messageSource.getMessage( "message.error.authorization.login.password.empty", new Object[]{login}, null ) );
		}
	
		return model;
	}

	@Override
	@Transactional(readOnly=true)
	public UserInfoForm getUserInfoForCurrentLoggedUser() throws AppException {
		SecurityContext securityContext = SecurityContextHolder.getContext();
		if(securityContext == null || securityContext.getAuthentication() == null || securityContext.getAuthentication().getPrincipal() == null){
			throw new AppException( messageSource.getMessage( "message.error.authorization.common", null, null ));
		}
		String login = null;
		Object principal = securityContext.getAuthentication().getPrincipal();
		if(principal instanceof UserDetails){
			login =((org.springframework.security.core.userdetails.User) principal).getUsername();
		}else {
			login = principal.toString();
		}
		
		if(StringUtils.isNotEmpty( login )){
			User userDB = userDao.getUserByLogin( login );
			if(userDB != null){
				return new UserInfoForm(userDB);
			}else{
				throw new AppException( 
						messageSource.getMessage( "message.error.authorization.user.null", new Object[]{login}, null ) );
			}
		}else{
			throw new AppException( 
					messageSource.getMessage( "message.error.authorization.login.password.empty", new Object[]{login}, null ) );
		}
	}
	
	
	@Override
	@Transactional(readOnly=false)
	public void registerNewUser(String p_login, String p_password, String p_firstName, String p_lastName) throws AppException {
		validateUserData( p_login, p_password, p_firstName, p_lastName );
		try{
			User existingUser = userDao.getUserByLogin( StringUtils.trim( p_login ) );
			if(existingUser != null){
				throw new AppException( 
					messageSource.getMessage( "message.error.registration.login.exist", new Object[]{p_login}, null ) );
			}
		
			Model model = new Model();
			model = (Model) modelDao.saveOrUpdate( model );
			
			Role userRole = (Role) roleDao.getRoleByName( AppConstants.ROLE_USER );
			User user = new User(userRole, model, AppConstants.ENTITY_STATE_ENABLED);
	
			user.setLogin( StringUtils.trim( p_login ) );
			user.setPassword( StringUtils.trim( p_password ) );
			user.setFirstName( StringUtils.trim( p_firstName ) );
			user.setLastName( StringUtils.trim( p_lastName ) );
			
			userDao.saveOrUpdate( user );
		}catch (AppException err) {
			log.error(messageSource.getMessage("log.error.registration", new Object[]{err.getMessage()}, null));
			throw new AppException(err.getMessage());
		}catch (Exception err) {
			log.error(messageSource.getMessage("log.error.registration", new Object[]{err.getMessage()}, null));
			throw new AppException(messageSource.getMessage("message.error.registration.common", null, null));
		}	
		
	}

	@Override
	@Transactional(readOnly=false)
	public void saveUserProfile(Integer p_id, String p_login, String p_password, String p_firstName, String p_lastName) throws AppException {
		validateUserData( p_login, p_password, p_firstName, p_lastName );
		try{
			if(p_id == null){
				throw new AppException( 
						messageSource.getMessage( "message.error.editprofile.user.notfound", null , null ) );
			}
			
			User existingUserWithSameLogin = userDao.getUserByLogin( StringUtils.trim( p_login ) );
			if(existingUserWithSameLogin != null && p_id != null && !existingUserWithSameLogin.getId().equals( p_id )){
				throw new AppException( 
					messageSource.getMessage( "message.error.registration.login.exist", new Object[]{p_login}, null ) );
			}
			
			User user = (User) userDao.getById( User.class, p_id );
			if(user != null){
				user.setLogin( StringUtils.trim( p_login ) );
				user.setPassword( StringUtils.trim( p_password ) );
				user.setFirstName( StringUtils.trim( p_firstName ) );
				user.setLastName( StringUtils.trim( p_lastName ) );
				userDao.saveOrUpdate( user );
			}else{
				throw new AppException( 
						messageSource.getMessage( "message.error.editprofile.user.notfound", null , null ) );
			}
		}catch (AppException err) {
			log.error(messageSource.getMessage("log.error.registration", new Object[]{err.getMessage()}, null));
			throw new AppException(err.getMessage());
		}catch (Exception err) {
			log.error(messageSource.getMessage("log.error.registration", new Object[]{err.getMessage()}, null));
			throw new AppException(messageSource.getMessage("message.error.registration.common", null, null));
		}	
	}
	
	/**
	 * Validates user data for empty values <br>
	 * @param p_login - user login; {@link String} <br>
	 * @param p_password - user password; {@link String} <br>
	 * @param p_firstName - user first name; {@link String} <br>
	 * @param p_lastName - user last name; {@link String} <br>
	 * @throws AppException - if exception was occurred
	 */
	private void validateUserData(String p_login, String p_password, String p_firstName, String p_lastName) throws AppException{
		if(StringUtils.isEmpty( p_login )){
			throw new AppException( 
					messageSource.getMessage( "message.error.registration.empty.login", null, null ) );
		}
		if(StringUtils.isEmpty( p_password )){
			throw new AppException( 
					messageSource.getMessage( "message.error.registration.empty.password", null, null ) );
		}
		if(StringUtils.isEmpty( p_firstName )){
			throw new AppException( 
					messageSource.getMessage( "message.error.registration.empty.firstname", null, null ) );
		}
		if(StringUtils.isEmpty( p_lastName )){
			throw new AppException( 
					messageSource.getMessage( "message.error.registration.empty.lastname", null, null ) );
		}
	}
}
